home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Language/OS - Multiplatform Resource Library
/
LANGUAGE OS.iso
/
oper_sys
/
quartz
/
quartz10.lha
/
src
/
runtime
/
processor.c
< prev
next >
Wrap
C/C++ Source or Header
|
1990-05-18
|
7KB
|
383 lines
/* Central grubby thread package routines: deal with operating environment
* -- don't compile with -pg */
#include <stdio.h>
#include <signal.h>
#include <parallel/microtask.h>
#include "thread.h"
#include "synch.h"
#include <usclkc.h>
#include "quartzcommon.h"
#include "profile.h"
#include "internal.h"
/* imported */
int exit();
void shminit();
char *shsbrk();
/* exported out of package */
shared int numProcessors = 1;
/* exported within package */
private PrivateProcessor pP = {0,0,0,0,0,0};
shared int processGroup;
shared int affinity = FALSE;
void IdleLoop(), Dummy(), KillAll(), Done(), ProcessorInit();
/* local to this file */
#ifndef PRESTO
static shared ReadyQ readyList[NUMPROCS];
static shared int numQueues = 1;
static shared ReadyQ *firstQ, *lastQ;
static shared usclk_t beginTime;
static shared usclk_t endTime;
void Startup(), ReadyqInit();
/* Note: it's simplest just to start everybody, make sure pP.thread
* is initialized, and then to start profiling */
main (argc, argv)
int argc;
char **argv;
{
char **p = argv + 1;
#ifdef PROFILE
int numProfilers = 1;
#endif
usclk_init();
ProcessorInit(0);
beginTime = GETUSCLK();
for (; *p && **p == '-'; p++)
switch (*(*p + 1))
{
#ifdef PROFILE
case 'p':
numProfilers = atoi(*p + 2);
break;
#endif
case 'n':
numQueues = numProcessors = atoi(*p + 2);
break;
case 'a':
affinity = TRUE;
break;
}
if (numProcessors <= 0)
{
printf("Too few processors: %d\n", numProcessors);
exit(1);
}
#ifdef PROFILE
if ((numProcessors+numProfilers) > NUMPROCS || numProfilers > MaxProfilers)
{
printf("Too many processors: %d %d\n", numProcessors, numProfilers);
exit(1);
}
ProcessorListInit();
ProfileInit(numProfilers);
MFork(ProfileStart, numProcessors, numProcessors + numProfilers, FALSE);
#else
if (numProcessors > NUMPROCS)
{
printf("Too many processors: %d\n", numProcessors);
exit(1);
}
#endif
PrivProcessorInit(0);
shminit();
StackpoolInit();
ThreadpoolInit();
ReadyqInit();
processGroup = getpgrp(0);
(void)ThreadStart(Main, NOJOIN, (char *)NULL, 2, argc, argv);
#ifdef PROFILE
ProfileSetAllBusy(numProcessors);
#endif
MFork(Startup, 1, numProcessors, TRUE);
/* PROBLEM: Can't call Startup directly here, since with
* optimizing on, it gets in-lined, and you lose bigtime */
}
void Startup (id)
{
fflush(stdout);
if (id != 0)
{
ProcessorInit(id);
PrivProcessorInit(id);
}
#ifdef PROFILE
ReplaceOnIdStack(IdleID, BusyState);
SetProfileOn();
#endif
INIT();
IdleLoop(0);
}
#define NextQ(q) ((q == lastQ) ? firstQ : (q + 1))
/* If finishing, then we enter with pP.thread == the finishing thread,
* if not, we enter with pP.thread = pP.idleThread
*/
void IdleLoop (finishing)
int finishing;
{
register Thread *t;
Stack *s;
register ReadyQ *q;
register int *bottom;
int *argv;
int i;
int *newfp;
if (finishing)
{
t = pP.thread;
s = t->stack;
if (t->join.status == NOJOIN)
{ ThreadFree(t); }
else /* you might think that we could just look at waiter, and resume
* if it is set -- but we must also be sure it has finished
* crawling off the stack */
{
SLNPAcquire(&t->join.lock);
if (t->join.status == CALLER_READY)
{ /* no need to release the lock -- just resume */
pP.thread = t->join.waiter;
#ifdef PROFILE
pP.proc->curThread = pP.thread;
#endif
StackpoolPut(s);
ThreadFree(t);
t = pP.thread;
RESUME(t);
}
else
{
#ifdef PROFILE
SetStateBlocked();
if (t->p)
t->p->number[0]++;
#endif
t->join.status = CALLEE_DONE;
SLNPRelease(&t->join.lock);
}
}
}
#ifdef PROFILE /* here's where we start spinning */
pP.proc->curThread = pP.thread = pP.idleThread;
NowIdle();
DecNominal();
AtomicIncrP(&(pP.lastLook->empty->number[0]));
/* So we'll see these as called from Idle Loop */
PushOnIdStack(pP.lastLook->empty, (unsigned int)SpinState);
PopOffIdStack();
PushOnIdStack(pP.lastLook->lock.p, (unsigned int)SpinState);
for (q = pP.lastLook;; q = NextQ(q))
{
ReplaceOnIdStack(pP.lastLook->empty, SpinState);
if (q->started)
{
ReplaceOnIdStack(q->lock.p, SpinState);
if (SLNPTestAndGet(&q->lock))
{
SetStateBusy();
if (t = q->started)
break;
else
SLNPRelease(&(q->lock));
}
}
}
q->started = t->next;
SLNPRelease(&(q->lock));
PopOffIdStack();
AtomicDecrP(&(pP.lastLook->empty->number[0]));
NowBusy(); /* here's where we stop spinning */
pP.proc->curThread = t;
pP.thread = t;
SetStateBusy();
#else
for (q = pP.lastLook;; q = NextQ(q))
{
if (q->started && SpinLockTestAndGet(&q->lock))
{
if (t = q->started)
break;
else
SpinLockRelease(&(q->lock));
}
}
q->started = t->next;
SpinLockRelease(&(q->lock));
pP.thread = t;
#endif
if (t->stack)
{
if (finishing)
StackpoolPut(s);
RESUME(t);
}
else
{
if (!finishing)
s = StackpoolGet();
t->stack = s;
bottom = &(s->space[StackSize]);
#ifdef PROFILE
/* probably only needed when PARANOID */
DUMMYFRAME(bottom); /* decrements bottom */
newfp = bottom;
#endif
argv = t->arglist;
for (i = t->numargs; i > 0; i--)
*--bottom = *argv++;
STARTUP(t, bottom, newfp);
THREAD_EXIT();
}
}
void ProgramDone ()
{
endTime = GETUSCLK();
printf("Time: %f\n", ((float)(endTime - beginTime)) / 1000000);
#ifdef PROFILE
ProfileFinish();
#else
if (numProcessors > 1)
KillAll();
exit(0);
#endif
}
void ReadyqInit ()
{
int i;
for (i = 0; i < numQueues; i++)
{
readyList[i].started = NULL;
SpinLockInit(&readyList[i].lock, "readyQ[i].lock");
#ifdef PROFILE
readyList[i].empty = SynchInit("readyQ[i].empty", VarSpinDependency);
#endif
}
firstQ = &readyList[0];
lastQ = &readyList[numQueues - 1];
}
#endif /* ifndef PRESTO */
#ifdef PROFILE
void ProfileStart (id)
{
ProcessorInit(id);
PrivProcessorInit(id);
ProfileExternal();
}
#endif
void KillAll ()
{
(void)signal(SIGUSR1, Dummy);
(void)killpg(processGroup, SIGUSR1);
}
void PrivProcessorInit (id)
int id;
{
pP.myId = id;
pP.seed = pP.myId;
#ifndef PRESTO
pP.lastLook = pP.putQ = &readyList[pP.myId % numQueues];
#endif
pP.deadThreads = NULL;
pP.deadCount = 0;
#ifdef PROFILE
pP.freeSynch = NULL;
pP.proc = &(processorList[pP.myId]);
pP.thread = pP.idleThread = pP.proc->curThread;
#endif
}
void ProcessorInit (id)
int id;
{
(void)signal(SIGUSR1, Done);
if (affinity && tmp_affinity(id) == -1)
fprintf(stderr, "Unable to affinity %d\n", id);
}
void TooSmall (n)
int n;
{
printf("Fatal Error: ThreadStart passed too many arguments %d\n", n);
fflush(stdout);
KillAll();
exit(1);
}
void Done ()
{
fflush(stdout);
fflush(stderr);
exit(0);
}
void MFork (func, lb, ub, self)
void (*func)();
int lb, ub;
int self;
{
int i;
int pid;
for (i = lb; i < ub; i++)
{
pid = fork();
if (pid == 0)
func(i);
else if (pid == -1)
KillAll();
}
if (self)
func(0);
}
int getid ()
{
return(pP.myId);
}
char *myshmalloc (n)
unsigned n;
{
char *p;
char *shmalloc();
if ((p = shmalloc(n)) == NULL)
{
fprintf(stderr, "Out of space\n");
fflush(stderr);
fflush(stdout);
KillAll();
exit(1);
}
return(p);
}
void Dummy ()
{}